#!/usr/bin/python
# -*- coding: utf8 -*-

from pyparsing import Literal, Regex, Keyword

from expresion import Expresion, Exp, Id, makeSintaxis
from lenguaje import Extension


class Let(Expresion):
    
    def __init__(self,toks):
        """
        Un Let estara compusto por una variable, un termino, y una expresion
        en donde las apariciones de la variable se reempazaran
        por el termino.
        """
        var,exp1,exp2 = toks
        self.var = var
        self.exp1 = exp1
        self.exp2 = exp2
    
    def reducir(self):
        """
        Para reducir un let, primero se reduce el termino asignado a la variable.
        Luego se reempaza en la expresion, el termino reducido en cada aparicion
        de la variable, finalmente se reduce éste ultimo termino con la sustutucion
        ya realizada.
        """
        definicion = self.exp1.reducir()
        expSubs = self.exp2.sustituir(self.var, definicion)
        return expSubs.reducir()
        
    def tipar(self,namespace):
        """
        gamma |> M : sigma,  gamma,{X:sigma} |> N: alpha
        -----------------------------------------------
        gamma |> let X = M in N : alpha
        """
        #gamma |> M : sigma
        tipo1 = self.exp1.tipar(namespace)
        
        name2 = dict(namespace)
        name2[self.var] = tipo1
        
        # gamma U {X:sigma} |> N: alpha
        tipo2 = self.exp2.tipar(name2)
        
        return tipo2
        
    def sustituir(self,var,expresion):
        """
        let X = M in N {X <- T} --> let X = M {X <- T}in N
        let X = M in N {Y <- T} --> let X in M {Y <-T} in N {Y <-T} si X != Y
        """
        exp1Sust = self.exp1.sustituir(var,expresion)
        if var != self.var:
            exp2Sust = self.exp2.sustituir(var,expresion)
        else:
            exp2Sust = self.exp2
        return Let([self.var,exp1Sust,exp2Sust])
    
    @classmethod
    def sintaxis(cls):
        # let M = N in O
        let = makeSintaxis("let", Id ,"=", Exp ,"in", Exp)
        return let
    
    def __str__(self):
        return "let %s = %s in %s" % (self.var, str(self.exp1), str(self.exp2))
        
        
extensionLet = Extension("Let", expresiones=[Let])
